home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
system
/
xpcmou10.zip
/
xpcmouse.asm
< prev
next >
Wrap
Assembly Source File
|
1994-12-16
|
76KB
|
2,349 lines
comment *
XPC-Mouse: POSITION CURSOR, COPY and PASTE in Dos Text Mode
Copyright (c) 1994 by Jürgen G. Weber and Grant B. Gustafson.
ALL RIGHTS RESERVED
Free for personal use under the Gnu Public License agreement, which is
distributed with this source. See the end of this file for a copy of
the License Agreement.
CREDITS
----------------------------------------------------------------------
Portions of this code originated with and were extracted from
PCMOUSE (c) 1992,1994 by Jürgen G. Weber
Wiesentalstraße 1
D-74523 Schwäbisch Hall
Germany - European Union
This ASM source written by GB Gustafson
113 JWB Math Dept Univ Utah
Salt Lake City, UT 84112
USA
in collaboration with Jürgen G. Weber to create this new product.
Portions of this ASM code also appeared in MOUSE2G, copyright (c)
1991, 1992 by GB Gustafson. Finally, credits are due to Al Williams,
for solid advice about TSR's, in his book "DOS 5: A Developers Guide",
M&T Press, 1991, and to Dave Williams, for his electronic reference on
DOS, especially the mouse information and interrupt details.
----------------------------------------------------------------------
XPC-Mouse
POSITION CURSOR, COPY and PASTE in Dos Text Mode
Function: Highlight text while left button is pressed. Left release
causes the selected text to be copied from the screen into
an internal pastebuffer. The right button (i.e., button2)
pastes the pastebuffer at the text cursor position. Left
button press of 1/6 second positions the text cursor
[defeatable]. Emacs/vi, matrix and Xterm style mouse action
methods. See the HELP at the end of the file for more.
MAKE: tasm xpcmouse
tlink xpcmouse
COMMAND LINE OPTIONS: /U /T /Q /N /R /Xddd /Bddd /M /K /P /A1 /A2 /A3 /C /H
See help text at the end of the file.
STARTUP DEFAULTS:
Auto default for video XOR highlight mask
/X80 for color modes (xor mask == 64+16 )
/M for mono modes (/M==/X119, xor mask == 64+32+16+4+2+1)
/A1 for Emacs/jed/vi arrow keys
/U, /Q, /N, /R, /T, /C, /?, /A2, /A3 defeated
/K and /P toggles are ON
/B128 is the default paste buffer size (16)(128)==2048 bytes
VERSIONS:
1.0 First public release.
Features of 1.0 inherited from Jürgen G. Weber's PC-Mouse versions 1.0-1.5:
Option /T, enable stuffing the paste buffer into the
keyboard buffer at every timer (int 1ch) tick.
Un-install Option /U. Mouse hardware reset after de-install.
8088 Version. Support mono, color, ega, vga text modes.
Option /Xddd for XOR mask
Option /Q for quiet start up
Option /N to defeat int 21h patch.
Option /R to reactivate TSR.
Pastebuffer compression and interrupt logic.
Install and de-install routines.
Features of 1.0 originating with this ASM source written by GB Gustafson:
Pressing the left button for 1/6 second positions the cursor.
Default /A1 for emacs/vi/jove/jed/epsilon mouse action.
Option /A2 is matrix mouse action, qedit/pi editors.
Option /A3 is for Xterm X10/X11 style escapes \033[M cb cx cy.
Works with remote jed/emacs/pi and extensible editors.
Toggle /A state dynamically using SHIFT-ALT-button1
with ring selection /A1 --> /A2 --> /A3 --> /A1.
Option /K defeats arrow keys and Xterm sequences.
Option /P defeats the pastebuffer.
ALT-button2 duplicates button3 (for 2-button mouse).
SHIFT-button1 toggles arrow keys on/off (see /K).
SHIFT-button2 toggles the pastebuffer on/off (see /P).
Option /M for monochrome Video mode (/M==/X119).
Unix file name selection on double-click using the idea
of the X11R5 Xterm character classes.
Hide mouse cursor after highlighting.
Auto default for video XOR highlight mask
/X80 for color modes (xor mask == 64+16 )
/M for mono modes (/M==/X119, xor mask == 64+32+16+4+2+1)
Help file dump /? gives switch information.
Author, copying and copyright switch /C for shorter signon.
Help file dump /H gives How-To information on mouse actions.
Dynamic buffer size up to max size compiled into program.
GNU license agreement.
Bug fixes:
/T was always ON. Reset to initially OFF. 1-Dec-94
/T ASM code caused characters to be lost on paste, traced to
recursive call of interrupt 1ch. Fixed by setting a flag to
bypass the second call (until the first one finished). This
bug was also in PCMOUSE 1.5, as observed under SunPC and sun4
OS.
/T off worked with paste, but not with arrow keys. Traced to
convoluted code which bypassed a call to stuff the keybuffer.
Fixed by having a central place where the mouse handler calls
the stuffer routines (near the exit).
TESTING:
The TSR was tested on about 5 different PC machines dating from 1984 to
1993 manufacture. CPU's tested: 80286, 80386SX, 80386DX, 80486SX,
80486DX. No workable XT 8088 could be found for testing! However, an XT
style non-extended keyboard was used and found to work.
Not tested with XT turned off in the ASM code. It will probably not
affect the TSR to do so, but the code as now written does not make use
of 80286+ opcodes or special features of int 16h. Some mouse drivers
and BIOS combinations disable the TSR unless it is compiled with the
8088 code control symbol "XT", because the nonresident CPU and mouse
BIOS tests cause the TSR to fail it's initial load. However, the
failure is superficial: it may only affect de-install /U on most
machines.
Loads high with devices "HIMEM.SYS" and "EMM386.EXE noems" /w control
"DOS=HIGH,UMB" under DOS 5.0 and 6.2. Loaded low with 386max, did not
test loaded into high umb's under 386max.
Works with DOS 4.01 under SoftPC version 3 (1992) for SUN4 OS (SunPC,
DOS emulator from Sun Microsystems, standard configuration). This is
the only mouse TSR known to work for DOS copy/paste/position in a unix
environment (X-windows, DOS emulator). Used with COMMANDO TSR, no
conflicts loaded low. Also works with WCED loaded high or low. In both,
the arrow key feature allows positioning on the command line.
MEMORY USAGE:
Complaints about the TSR's resident size should take note that it will
reside in high memory and eat about 4.6k. By cutting out the
pastebuffer, using option "/B0 /P", usage can be reduced to 2.6k. A
recompile, removing the arrow key code or the pastebuffer code will
cause correspondingly significant code size reductions. Resident code
size below 2.2k is possible, without paste buffer features.
EDITORS TESTED:
Remote over modem line: Emacs, vi, jed, jove, pi.
Local PC: epsilon, pi, qedit.
Special interfaces tested: emacs, jed, pi.
For these, we had to write extension code for the editor involved, or
else modify the sources. The standard "mousex.sl" in the JED library
works as written. PI needed the unix Xterm mouse code enabled for
compilation under DOS. EMACS needed a special LISP function for the
mouse motions.
* ; End comment
PVERSION equ '1.0: 3 Dec 1994'
TRUE equ -1
FALSE equ not TRUE
;
; Compile Time switches that change the final EXE size.
; EXE size is most affected by BUFFERLEN value. The
; actual resident code is about 2.25k total (help text not resident).
; The paste buffer is variable, size 0 to BUFFERLEN, and this adds
; up to 2k to the resident code size.
;
XT equ TRUE ; TRUE for PC or XT 8086/8088 cpu and old bios.
; FALSE for 80188+ cpu, new bios and 286 opcodes.
BUFFERLEN EQU 2048 ; Max buffer size for copying text and attributes.
; Enough for a full screen. Blanks are compressed.
; 1024 is enough for 1/2 of screen. Use /Bddd
; option to set runtime buffer size (can be zero).
; Code actually uses "BUFLEN" variable.
;
; Masks for mouse events
;
M_MOVED EQU 1B ;bit 0 mouse movement
M_LT_PRESSED EQU 10B ;bit 1 left button pressed
M_LT_RELEASED EQU 100B ;bit 2 left button released
M_RT_PRESSED EQU 1000B ;bit 3 right button pressed
M_RT_RELEASED EQU 10000B ;bit 4 right button released
M_MI_PRESSED EQU 100000B ;bit 5 middle button pressed (Mouse Systems)
M_MI_RELEASED EQU 1000000B ;bit 6 middle button released (Mouse Systems)
SPEED_LDC equ 9 ; Double click threshold 9/18.2 seconds
;
if not XT
.286 ; the times, they're a-changing ... memento mori 808[6|8]
endif
locals ; makes the local @@Label possible
; Useful macros
;
PUSHR macro regs ;; eg: PUSHR <bx,ax,cx>
local reg
irp reg,<regs>
push reg
endm
endm
POPR macro regs ;; eg: POPR <cx,ax,bx>
local reg
irp reg,<regs>
pop reg
endm
endm
XPUSHA macro
if XT
PUSHR <AX,BX,CX,DX,BP,SI,DI>
else
pusha
endif
endm
XPOPA macro
if XT
POPR <DI,SI,BP,DX,CX,BX,AX>
else
popa
endif
endm
code segment
assume cs:code
begin_resident equ $ ; All resident code starts here
flag_int21 db FALSE ; TRUE if int 21h is patched.
flag_int1c db FALSE ; TRUE to stuff keybuffer at timer ticks.
counter_int10 dw 0 ; Incremented at each call of int 10h
flag_Left db FALSE ; TRUE if left button was pressed.
flag_Right db FALSE ; TRUE when right button pressed.
flag_Highlight db FALSE ; TRUE if an area is highlighted on screen.
flag_MouseOn db FALSE ; TRUE if mouse cursor is on.
flag_CtrlRight db FALSE ; TRUE if last click was ctrl-right
old_mousemask dw 0 ; Mask used by last mouse handler.
old_mouseAddr dw 0,0 ; Far address of last mouse handler.
PositionLeft dw 0 ; Position of mouse at left click
NextPositionLeft dw 0 ; Position of mouse at a later left click
xor_mask db 01010000b ; XOR mask for selected screen area
xor_pointer dw 0 ; Pointer to screen area to be xor'ed
lastChar db 0 ; Saved character from failed key-stuff.
lineSize dw 0 ; Characters per line on screen
videosegment dw 0 ; Segment of screen memory
videoOffset dw 0 ; Offset into video page
lasttime dw 0,0 ; System time at last left click
counter_blanks db 0 ; Counter for blanks yet to be stuffed.
nextpair dw offset pastebuf ; Pointer to next character pair in paste buffer.
lastpair dw offset pastebuf ; Pointer to end of text in paste buffer.
flag_arrowkeys db 1 ; Arrowkeys initially ON
flag_pastebuffer db 1 ; Pastebuffer initially ON
flag_editor db 1 ; 1=emacs/vi/jove/jed, 2=matrix, 3=Xterm,
flag_double db FALSE ; TRUE if left button was double-clicked
flag_busy_stuffing db 0 ; TRUE if stuffing keys (see new int 1ch)
flag_doButton13 db FALSE ; TRUE if we are to send button1 + button3
flag_doButton2 db FALSE ; TRUE if we are to send button2
flag_doButton3 db FALSE ; TRUE if we are to send button3
current_X dw 0 ; Current mouse X coordinate (transient)
current_Y dw 0 ; Current mouse Y coordinate (transient)
EndOfBuffer dw pastebuf+BUFFERLEN-1 ; Address of end of paste buffer
MAX_of_A equ 4 ; max number of /A options (1,2,3) plus 1
SPEED_LC equ 3 ; About 3/18.2 sec left button press required.
col_present db 0 ; col for text cursor (not mouse cursor!)
row_present db 0 ; row for text cursor
col_target db 0 ; col where left button was pressed
row_target db 0 ; row where left button was pressed
; Xterm escapes for buttons 1,2,3 are in format ASCII,SCANCODE
; because they are to be stuffed directly into the keybuffer.
;
; Escape sequence for button 1
Button1_ESC db 1bh, 01h ; ESC
db '[',1ah ; [
db 'M',32h ; M
db 20h,39h ; SPACE
Button1_COL db 00h,00h ; Column position
db 00h,00h ; Row position
Button1_LEN equ 6 ; Number of pairs in sequence
; Escape sequence for button 2
Button2_ESC db 1bh, 01h ; ESC
db '[',1ah ; [
db 'M',32h ; M
db 21h,02h ; SPACE+1
Button2_COL db 00h,00h ; Column position
db 00h,00h ; Row position
Button2_LEN equ 6 ; Number of pairs in sequence
; Escape sequence for button 3
Button3_ESC db 1bh, 01h ; ESC
db '[',1ah ; [
db 'M',32h ; M
db 22h,28h ; SPACE+2
Button3_COL db 00h,00h ; Column position
db 00h,00h ; Row position
Button3_LEN equ 6 ; Number of pairs in sequence
;
Xterm_PAD equ ' '+1 ; Offset for Xterm escapes row,col
;
; Xterm-style char classes for double-click
; Inequality a<=x<=b coded as "db a,b" below.
;
unix_pairs db 9 ; Number of active pairs below
unix_ranges db 35,35 ; # (pound)
db 45,57 ; -./0123456789
db 64,90 ; @ABCDEFGHIJKLMNOPQRSTUVWXYZ
db 92,92 ; \ (backslash)
db 95,95 ; _ (underline)
db 97,122 ; abcdefghijklmnopqrstuvwxyz
db 126,126 ; ~ (tilde)
db 128,165 ; European letters
db 224,238 ; Greek letters and infinity
db 0,0 ; extra space for more combos
db 0,0 ; This table can be changed dynamically
db 0,0 ; on program load or restart (not implemented).
db 0,0 ; If you change this, also change
db 0,0 ; variable "unix_pairs" above!
;
; The MOUSE HANDLER is called by the mouse driver
; if an event occurs which matches the CX mask
; that was supplied at the time of installation.
; ENTRY: The mouse device driver supplies this info:
; AX=Mouse event bits
; BX=button state: bit0=left, bit1=right, bit2=center
; CX=current X coordinate, DX=current Y coordinate
; SI=raw Y mickeys, DI=raw X mickeys
; DS=driver's data segment
;
MouseHandler proc far ; Handler ends with far ret
XPUSHA ; handler can't modify registers
push ds ; can't call DOS or BIOS
;
; Do not let mouse routines happen if interrupt 10h is active
; or is there is no text mode active (eg, graphics modes ==> no mouse)
;
cmp counter_int10,0 ; Int 10h interrupted?
jne short @@exit1 ; Yes, then get out of here.
@@not_in10:
mov current_X,cx ; Save button X and Y coordinates
mov current_Y,dx ; from this call.
push ax
mov ax,40h ; bios data area segment address
mov ds,ax ; Use DS to read bios variables.
pop ax
cmp byte ptr [ds:49h],3 ; BIOS current video mode
jna short @@test_events
cmp byte ptr [ds:49h],7 ; BIOS current video mode
jz short @@test_events
cmp byte ptr [ds:49h],13h ; Other video modes are graphics
jna short @@exit1
cmp word ptr [ds:4ch],0800h ; Assume text mode if video memory
jna short @@test_events ; size is 4096k bytes or less.
@@test_events:
;
; TEST button event flags passed to handler in register AX
; In: AX=mouse event bits from device driver
;
@@tst_moved:
test ax,M_MOVED ; mouse was moved
jz short @@tst_released
jmp @@mouse_moved
@@tst_released:
test ax,M_LT_RELEASED ; a button was released
jz short @@tst_right
jmp @@left_released
@@tst_right:
test ax,M_RT_PRESSED ; button2 (right on 2-button mouse)
jz short @@tst_left
jmp @@test_shift_right
@@tst_left:
test ax,M_LT_PRESSED ; button1 (left button)
jz short @@tst_middle
jmp @@test_shift_left
@@tst_middle:
test ax,M_MI_PRESSED ; button3 (middle on mouse systems)
jz short @@tst_exit
jmp @@middle_pressed
@@tst_exit:
@@exit1:
jmp @@exit
;
; END of TEST button events
;
@@left_released:
cmp flag_Left,TRUE ; If left not pressed, then hide mouse.
jne short @@skip_cursor
cmp flag_double,TRUE
je @@copy_region1
mov ax,NextPositionLeft
cmp ax,PositionLeft
jz short @@no_selection ; nothing at all marked
@@copy_region: ; Something to copy
cmp flag_Left,FALSE ; If left not pressed, then hide mouse.
je short @@skip_cursor
@@copy_region1:
mov flag_double,FALSE ; Otherwise, copy screen text to
mov flag_Highlight,TRUE ; the pastebuffer.
mov flag_Left,FALSE
call Fill_pastebuffer
cmp flag_pastebuffer,1 ; Pasting enabled?
jne short @@copy_region2 ; No, then maybe send Xterm info
or ax,ax ; Any chars copied to pastebuffer?
jz short @@skip_cursor ; No, then hide mouse.
@@copy_region2:
mov flag_doButton13,TRUE ; Send button1+button3 info
jmp short @@skip_cursor
@@no_selection:
; Mouse was released at same location. Test if enough time has
; elapsed to call it a cursor positioning click.
call ClickTimeCursor
jnz short @@skip_cursor ; Not enough time, hide mouse.
call set_cursor ; set text cursor position
@@skip_cursor:
mov flag_Left,FALSE
cmp flag_MouseOn,TRUE ; turn off mouse cursor
jnz short @@no_hide ; because it confusing to have
call HIDE_MOUSE ; two cursors after we move the
mov flag_MouseOn,FALSE ; text cursor or highlight an area
@@no_hide:
@@exit2:
jmp @@exit
; TOGGLE: shift-button2 == pastebuffer ON/OFF
@@test_shift_right:
test byte ptr [ds:17h],3 ; Keyboard flag, bit 0 and bit 1 = SHIFT
jz short @@rt_pressed
mov al,1
sub al,flag_pastebuffer
mov flag_pastebuffer,al
jmp short @@exit2
;
; TOGGLE /A1-/A3 states by mouse actions
; button1+button2 == toggle to next of /A1 to /A3 in circular fashion.
;
@@rt_pressed:
cmp flag_Left,TRUE
jz short @@exit2 ; both buttons simultaneously pressed
@@do_insert:
;
; If ALT-button2, then simulate button 3 on 3-button mouse
;
test byte ptr [ds:17h],8 ; Keyboard flag, bit 3 = ALT
jnz short @@do_insert0
mov flag_doButton2,TRUE; Send button2 info later on
jmp short @@do_insert1
@@middle_pressed: ; Extra mouse button pressed (button3)
@@do_insert0: ; or equivalent ALT-button2 was pressed
mov flag_doButton3,TRUE; Send button3 info later on
jmp short @@exit2 ; No paste, we are done!
@@do_insert1:
cmp flag_pastebuffer,1 ; Are we pasting the buffer?
jne short @@test_ctrl ; No, then go test for ctrl key
mov flag_Right,TRUE
mov bx,offset pastebuf
mov nextpair,bx ; pointer reset to start of pastebuf
; MOUSE ACTION: Add CR to end of pastebuffer output.
; If the right mouse button and CTRL were pressed, then
; set a flag to output a CR after the pastebuffer is finished.
@@test_ctrl:
test byte ptr [ds:17h],4 ; Keyboard flag, bit 2 = CTRL
jz short @@test_ctrl1
mov flag_CtrlRight,TRUE
@@test_ctrl1:
@@exit3:
jmp @@exit
@@mouse_moved:
cmp flag_MouseOn,TRUE
jz short @@is_on
call SHOW_MOUSE ; switch on cursor after first movement
mov flag_MouseOn,TRUE
@@is_on:
cmp flag_Left,TRUE
jz short @@do_mark ; highlight if left button still pressed
jmp @@exit
@@do_mark:
call highlight_text ; In: cx,dx = mouse X,Y
jmp short @@exit3 ; Updates NextPositionLeft.
;
; TOGGLE: shift-button1 == Arrowkeys ON/OFF
@@test_shift_left: ; Test keyboard flag byte
test byte ptr [ds:17h],4 ; bit 2 = CTRL
jz short @@test_left_shift1
jmp @@exit ; Nothing for ALT-left or CTRL-left
@@test_left_shift1:
test byte ptr [ds:17h],3 ; bit 1 = LEFT SHIFT, bit 0 = RIGHT SHIFT
jz short @@left_pressed
test byte ptr [ds:17h],8 ; bit 3 = ALT
jnz short @@test_left1
mov al,1
sub al,flag_arrowkeys ; Toggle the flag on/off (1 or 0)
mov flag_arrowkeys,al
jmp short @@exit
@@test_left1:
mov al,flag_editor
inc al
cmp al,MAX_of_A ; Toggle the cursor positioning
jb short @@left1
mov al,1
@@left1: ; Flag will be 1,2,..,(MAX_of_A-1)
mov flag_editor,al
jmp short @@exit ; toggle finished
@@left_pressed: ; get screen data after left click
mov ax,[ds:4ah] ; Characters per row for this video mode
mov lineSize,ax
mov ax,[ds:4eh] ; Offset for current video page
mov videoOffset,ax
mov ax,[ds:63h] ; Mono/Color BIOS word
cmp ax,3B4h ; monochrome ?
mov videosegment,0b000h ; mono address
jz short @@left_pressed1
mov videosegment,0b800h ; color address
@@left_pressed1:
call unhighlight_text ; remove previous highlighting
mov flag_Right,FALSE
mov counter_blanks,0
mov flag_Left,TRUE ; Set left button press state
call xy2offs ; In: cx,dx Out: ax
mov PositionLeft,ax ; Save mouse position and reset both
mov NextPositionLeft,ax ; because selected text was trashed.
sub ax,2
mov xor_pointer,ax
; SPEED_LDC is the number of ticks of the system clock, 18.2 per
; second, in which a left double-click must occur. Shorter times
; are not considered double-click candidates.
mov flag_double,FALSE ; Assume not a double-click.
call ClickTimeDouble ; Uses: AX
jz short @@exit ; Not enough time.
; double click
mov flag_double,TRUE
call highlight_word
@@exit:
call stuff2keybuffer ; to end a possibly active int 16h,0
pop ds
XPOPA
ret
MouseHandler endp
SHOW_MOUSE proc
push ax
mov ax,1 ; Function show mouse
int 33h
pop ax
ret
SHOW_MOUSE endp
HIDE_MOUSE proc
push ax
mov ax,2 ; Function hide mouse
int 33h
pop ax
ret
HIDE_MOUSE endp
; calculate video offset from x and y
; In: x=cx, y=dx ; Left upper corner of screen is x=0, y=0.
; Out: ax := offs = y*80+x
; USES: ax
xy2offs proc
PUSHR <dx,cx>
shr cx,1
shr cx,1
shr cx,1
cmp lineSize,40
jnz short @@no_40
shr cx,1 ; divide by 16 if there are 40 columns per line
@@no_40:
shr dx,1
shr dx,1
shr dx,1
mov ax,dx
mul lineSize
add ax,cx ; +=x
add ax,ax ; 2 bytes per character
add ax,videoOffset
inc ax ; -> attribute
POPR <cx,dx>
ret
xy2offs endp
;
; Calculate from offset into screen memory the screen row, col
; Left upper corner of screen is row=0, col=0 [rows 0..24, cols 0..79]
; In: ax=offset into screen memory (includes attribute counts).
; Out: ah := col, al = row
offs2xy proc
push bx
shr ax,1 ; divide numerator AX by 2
mov bx,lineSize ; bl=denominator
idiv bl ; AX/bl --> al=quotient, ah=remainder
pop bx
ret
offs2xy endp
; show or hide mark on screen
; In: AX=characters*2 for XOR operation
; USES: AX
xor_screen proc
PUSHR <bx,cx,dx,ds>
call HIDE_MOUSE ; in order not to destroy the mouse cursor
mov bx,xor_pointer
mov cl,xor_mask
mov dx,videosegment
mov ds,dx
sar ax,1 ; Divide by 2 to get number of characters
or ax,ax
jns short @@pos_loop
; mouse was moved to the left
@@neg_loop:
xor byte ptr [ds:bx],cl ; xor_mask applied to screen byte
sub bx,2
inc ax ; inc, as counter is negative
jnz short @@neg_loop
jmp short @@exit
; mouse was moved to the right
@@pos_loop:
add bx,2
xor byte ptr [ds:bx],cl
dec ax
jnz short @@pos_loop
@@exit:
call SHOW_MOUSE
mov xor_pointer,bx
POPR <ds,dx,cx,bx> ; PUSHR <bx,cx,dx,ds>
ret
xor_screen endp
; Highlight single word chosen by double click
; USES: AX
highlight_word proc
PUSHR <bx,ds>
mov lasttime,0
mov lasttime+2,0 ; prevent Triple click
push videosegment
pop ds
mov bx,PositionLeft ; point to attribute
dec bx
call @@tst_letter
jc @@exit ; clicked to void
@@go_left: ; search for word begin
call @@tst_letter
dec bx
dec bx
jnc @@go_left
add bx,5 ; points to attribute again
mov PositionLeft,bx
dec bx
dec bx
mov xor_pointer,bx
dec bx
@@go_right: ; search for word end
inc bx
inc bx
call @@tst_letter
jnc @@go_right
mov ax,bx
inc bx
mov NextPositionLeft,bx
sbb ax,xor_pointer ; cy is 1 from tst_let
call xor_screen ; Uses ax
@@exit:
POPR <ds,bx>
ret
; @@tst_letter --- Test character classes.
; Do this like Xterm, with a string of data pairs:
; 35:35,45:57,64:90,95:95,97:122,128:165
; USES: AX
;
@@tst_letter:
push si
mov ax,offset unix_ranges
mov si,ax
mov ah,0
mov al,[ds:bx]
@@tst_loop:
cmp ah,unix_pairs
je @@tst_failed
inc ah
cmp byte ptr [cs:si],al
jbe short @@tst_1
inc si
inc si
jmp short @@tst_loop
@@tst_1:
inc si
cmp al,byte ptr [cs:si]
jbe short @@tst_worked
inc si
jmp short @@tst_loop
@@tst_worked:
clc
jmp short @@tst_exit
@@tst_failed:
stc
@@tst_exit:
pop si
ret
highlight_word endp
;
; Highlight screen area that was traversed during mouse motion.
; In: cx,dx = mouse X,Y
; USES: AX
highlight_text proc
call xy2offs ; In: cx,dx Out: ax
push ax ; New left mouse position
sub ax,NextPositionLeft ; ax/2 == number of positions traversed
pop NextPositionLeft ; update new mouse position
jz short @@exit ; too little mouse motion
call xor_screen ; In: AX=number positions times 2
mov flag_Highlight,TRUE
@@exit:
ret
highlight_text endp
; Remove highlight from screen area.
; Uses: AX
unhighlight_text proc
push bx
cmp flag_Highlight,TRUE
jnz short @@exit ; Highlighting was already undone.
mov bx,PositionLeft
mov ax,NextPositionLeft
sub ax,bx
je short @@exit ; Nothing highlighted
mov bx,PositionLeft
dec bx
dec bx
mov xor_pointer,bx ; Set pointer into screen memory
call xor_screen ; Unhighlight. Uses: AX=Length of region
mov flag_Highlight,FALSE
@@exit:
pop bx
ret
unhighlight_text endp
;
; Fill_pastebuffer: Read the selected characters into pastebuffer.
; Called after double click or left selection.
;
Fill_pastebuffer proc
PUSHR <bx,cx,dx,si,di,es>
cmp flag_pastebuffer,1 ; Are we supposed to paste?
jne short @@exit_nochars ; No, then quit with no chars.
push cs ; Yes, then fool with pastebuffer
pop es ; store chars to es:di
mov bx,PositionLeft
mov cx,NextPositionLeft
dec bx
dec cx ; doesn't point to attribute any more now
mov dx,2
mov di,offset pastebuf
cmp bx,cx
jc short @@no_swap ; not marked from right to left
jz short @@exit_nochars ; nothing at all marked
xchg bx,cx ; now from left to right
add bx,dx
add cx,dx
cmp bx,cx
jnz short @@no_swap ; something marked
@@exit_nochars: ; Nothing marked
mov ax,0
jmp @@@exit
@@no_swap:
cld
mov ax,videosegment
mov ds,ax
mov ah,0
@@rd_loop:
cmp di,EndOfBuffer
ja short @@no_bln_left ; Buffer is full
mov al,[ds:bx]
cmp al,' '
ja short @@normal_char
inc ah ; ah == compression count for ' '
cmp ah,32 ; ah == 32 means 32 ' ' characters.
jnz short @@next_char
stosb ; Otherwise, store coded byte
mov ah,0 ; and continue with the next one
jmp short @@next_char
@@normal_char:
cmp ah,0 ; are there blanks left unstored ?
jz short @@no_blks ; no, it's a normal char
xchg al,ah ; yes, it's a coded ' '
stosb ; Squirrel away coded ' ' byte
xchg al,ah
mov ah,0 ; Attribute byte is 0 for coded ' '
@@no_blks:
stosb ; store char, coded or otherwise
@@next_char:
add bx,dx ; next char on screen
; Test, if at line end on screen
; condition: screen pos mod (characters per line) == 0
PUSHR <dx,cx,ax>
xor dx,dx ; must be 0 before divide
mov ax,bx ; screen pos
sub ax,videoOffset
mov cx,lineSize ; CX == 40 or CX == 80
add cx,cx ; *2 because of ascii,attribute
div cx
or dx,dx ; Division remainder == 0 ?
jnz short @@not_eol
@@go_back: ; discard blanks until end of line
dec di
cmp byte ptr [es:di],' '
ja short @@no_back
cmp byte ptr [es:di],0 ; end of previous line ?
ja short @@go_back
@@no_back:
inc di
mov al,dl ; 0 to mark end of line
stosb
pop ax ; ax must have been pushed last
xor ah,ah ; Zero the ' ' counter
push ax
@@not_eol:
POPR <ax,cx,dx>
cmp bx,cx ; at the end of selected area ?
jnz short @@rd_loop
or ah,ah ; blanks left to store ?
jz short @@no_bln_left
mov al,ah
stosb ; store remaining blanks
@@no_bln_left:
mov lastpair,di ; pointer to end of used buffer area
@@exit:
mov ax,1
@@@exit:
POPR <es,di,si,dx,cx,bx> ; PUSHR <bx,cx,dx,si,di,es>
ret
Fill_pastebuffer endp
; ClickTimeDouble --- Return Z if time since last left click too short.
; Uses: AX
ClickTimeDouble proc
PUSHR <cx,dx>
mov ah,0
int 1ah ; read system clock counter
mov ax,0 ; Return AX==0 in Z flag
push cx ; high word
push dx ; low word
sub dx,lasttime
sbb cx,lasttime+2 ; cx:dx = ticks since last click
pop cs:lasttime
pop cs:lasttime+2 ; save new clock time
or cx,cx
jnz short @@exit ; Exceeded 65535/18.2 seconds
cmp dx,SPEED_LDC
ja short @@exit ; Exceeded SPEED_LDC seconds
mov ax,1 ; Was a double-click.
@@exit:
or ax,ax
POPR <dx,cx>
ret
ClickTimeDouble endp
; ClickTimeCursor --- Return Z if time since last left click too short.
; Uses: AX
ClickTimeCursor proc
PUSHR <cx,dx>
mov ah,0
int 1ah ; read system clock counter
mov ax,0 ; Return AX==0 in Z flag
sub dx,lasttime
sbb cx,lasttime+2 ; cx:dx = ticks since last left press
or cx,cx
jnz short @@exit ; Exceeds 65535/18.2 seconds
cmp dx,SPEED_LC
ja short @@exit ; Exceeds 3/18.2 seconds
mov ax,1
@@exit:
or ax,ax
POPR <dx,cx>
ret
ClickTimeCursor endp
; install mouse handler
InstallMouseHandler proc far
PUSHR <es,dx,cx,ax>
; Software Reset, to put handler into defined state
mov ax,21h
int 33h
push cs
pop es
mov dx,offset MouseHandler
mov cx,(M_MOVED or M_LT_PRESSED or M_LT_RELEASED or M_RT_PRESSED or M_MI_PRESSED)
mov ax,14h ; Swap Interrupt Subroutines
int 33h
; ignore old interrupt routine
POPR <ax,cx,dx,es>
ret
InstallMouseHandler endp
; Get characters from the paste buffer
; Characters are 33 to 255
; A character nnn less than 33 represents nnn Blanks
; End of line is marked with 0
;
INCZ macro op ; if Z op++
local not_zero
jnz short not_zero
inc op
not_zero:
endm
; In: Nothing
; Out: ZF flag == buffer empty else AL == char found
; Uses: AX, flags
;
GetPastebuffer2AL proc
push bx
cmp flag_pastebuffer,0
jz short @@buf_empty
cmp flag_Right,FALSE
jz short @@buf_empty
cmp counter_blanks,0
jz short @@no_bln_lft
dec counter_blanks
INCZ nextpair
mov al,' '
jmp short @@char_found
@@no_bln_lft:
mov bx,nextpair
cmp bx,lastpair
jnz short @@not_empty
cmp flag_CtrlRight,TRUE ; append CR, too ?
jnz short @@buf_empty
mov flag_CtrlRight,FALSE ; Mark that we did it.
mov al,13 ; return CR
jmp short @@char_found
@@not_empty:
mov al,[cs:bx] ; get next character
cmp al,0 ; end of line ?
jnz short @@not_eol
mov al,13
inc nextpair
jmp short @@char_found
@@not_eol:
cmp al,' '
jbe short @@blanks
inc nextpair
jmp short @@char_found
@@blanks:
mov ah,al
mov al,' '
dec ah
mov counter_blanks,ah
INCZ nextpair ; blanks exhausted
@@char_found:
clc
jmp short @@exit
@@buf_empty:
stc
@@exit:
pop bx
ret
GetPastebuffer2AL endp
; Patch for EXEC Function
new_21h proc
cmp ax,4b00h ; exec
jz short @@new_exec
jmp @@doit
@@new_exec:
; activate mouse handler, as it is possible,
; that a program that changed the mouse handler
; did so by starting COMMAND.COM
push bp
mov bp,sp
; stack now:
; bp -> bp
; bp+2 -> ip
; bp+4 -> cs
; bp+6 -> flags
XPUSHA
push es
mov cx,0 ; get old interrupt info
mov ax,14h ; Swap interrupt subroutines
int 33h
mov old_mousemask,cx ; save old mouse mask
mov old_mouseAddr,dx
mov old_mouseAddr+2,es ; save address of old routine
call InstallMouseHandler
pop es
XPOPA
push old_mousemask ; push to enable recursion
push old_mouseAddr
push old_mouseAddr+2
push [bp+6] ; take flags of original int and
; simulate int operation
call dword ptr [cs:old_21h]
; iret after original int 21h leads to here
pop old_mouseAddr+2
pop old_mouseAddr
pop old_mousemask
pop bp
pushf
XPUSHA
mov ax,21h ; Software Reset
int 33h
cmp cs:killed_flg,TRUE ; /U in the mean time ?
jz short @@no_res_old
mov cx,old_mousemask ; set old routine again
les dx,dword ptr old_mouseAddr
mov ax,14h
int 33h
@@no_res_old:
XPOPA
popf
retf 2 ; ignore old flags as EXEC returns
; result status in flag register
@@doit:
db 0eah ; jmp far
old_21h dw 0,0
killed_flg db FALSE
new_21h endp
; Patch for Interrupt 10h
old_10h dw 0,0
new_10h proc
cmp flag_MouseOn,TRUE
jnz short @@no_hide
call HIDE_MOUSE
mov flag_MouseOn,FALSE
@@no_hide:
cmp flag_Highlight,TRUE
jnz short @@no_un_sel
push ax
call unhighlight_text ; Uses AX
pop ax
mov flag_Left,FALSE
@@no_un_sel:
pushf ; simulate int
inc counter_int10 ; Mark int 10h active
call dword ptr [old_10h]
dec counter_int10 ; Mark int 10h inactive
iret
new_10h endp
; BIOD data segment equates
;
biosdata segment at 40h
org 1ah
headptr dw (?) ; pointer to next key entry to read
tailptr dw (?) ; pointer to last read key entry
org 80h
bufstrt dw (?) ; pointer to start keyboard buffer
bufend dw (?) ; pointer to end keyboard buffer
biosdata ends
stuffkeyCX proc
; substitute for Int 16h, function 5
; in: ch=scan code
; cl=ascii
; out: al=0 success
; al=1 buffer full
; USES: ax,cx
;
push ds
push bx
pushf
cli
mov ax,biosdata
mov ds,ax
mov ax,ds:tailptr
add ax,2
mov bl,1
cmp ax,ds:headptr ; don't want tailptr == headptr after exit
jz short @@full ; because it means buffer is empty!
cmp ax,ds:bufend ; Ringbuffer, may need to bump pointer
jnz short @@no_wrap
mov ax,ds:bufstrt ; wrap around was required
@@no_wrap: ; AX == new tailptr position
cmp ax,ds:headptr ; don't want tailptr == headptr after exit
jz short @@full ; because it means buffer is empty!
@@go_ahead:
mov bx,ds:tailptr ; old tailpointer
mov [ds:bx],cx ; store scan+ascii
mov ds:tailptr,ax
mov bl,0
@@full:
mov al,bl
popf
pop bx
pop ds
or al,al ; 0 == save was successful
ret ; sti not appropriate here
stuffkeyCX endp
;
; Test keyboard buffer for room to copy scan codes
; In: AL == # scan codes
; Out: NZ flag set if no room exists
; Uses: AX, FLAGS
Check4Room proc
PUSHR <ds,bx,ax>
mov bl,al ; Number of pairs required
mov ax,biosdata
mov ds,ax
mov ax,ds:tailptr
@@loop:
add ax,2
cmp ax,ds:bufend ; Ringbuffer, may need to bump pointer
jnz short @@no_wrap
mov ax,ds:bufstrt ; wrap around was required
@@no_wrap: ; AX == new tailptr position
cmp ax,ds:headptr ; don't want tailptr == headptr after exit
jz short @@full ; because it means buffer is empty!
@@go_ahead:
dec bl
or bl,bl
jnz short @@loop
@@full:
or bl,bl ; 0 == it worked, NZ == failed
POPR <ax,bx,ds>
ret
Check4Room endp
;
; Patch for int 1ch
;
new_1ch proc
pushf
cmp flag_busy_stuffing,1 ; In routine "stuff2keybuffer"?
je @@skip ; wait until next timer tick
call stuff2keybuffer ; write characters into keyboard buffer
@@skip:
popf
db 0eah ; Code for jmp far
old_1ch dw 0,0
new_1ch endp
; Patch for int 16h
new_16h proc
cmp ah,MOUSE_FN ; New function for int 16h
jnz short @@skip1
dec ah ; AH unchanged by normal bios call
mov cx,IDENTCODE ; Return identity code
push cs ; and far address of the pastebuffer
pop es ; es:bx := buffer address
mov bx,offset pastebuf
iret
@@skip1:
pushf
cmp flag_busy_stuffing,1 ; In routine "stuff2keybuffer"?
je @@skip2 ; wait until next timer tick
call stuff2keybuffer ; else, write character into keyboard buffer
@@skip2:
popf
db 0eah ; Code for jmp far
old_16h dw 0,0
new_16h endp
;
; Arrow key routines, does not depend on Xterm standard.
;
LeftArrow proc
mov cx,4b00h ;cl=0, ch=4bh Left arrow key
call stuffkeyCX ; uses ax,cx
ret
LeftArrow endp
DownArrow proc
mov cx,5000h ;cl=0, ch=50h Down arrow key
call stuffkeyCX ; uses ax,cx
ret
DownArrow endp
UpArrow proc
mov cx,4800h ;cl=0, ch=48h Up arrow key
call stuffkeyCX ; uses ax,cx
ret
UpArrow endp
RightArrow proc
mov cx,4d00h ;cl=0, ch=4dh Right arrow key
call stuffkeyCX ; uses ax,cx
ret
RightArrow endp
;
; Xterm standard uses the sequence "ESC [ M cb cx cy" where
; cb=32 for press left-button, cb=34 for press right-button, cb=33 for
; press middle button, cb=35 for release (any) button, cx=32+1+col,
; cy=32+1+row where (0,0) is upper left corner of screen
;
; Stuff a string of scan code data into the keyboard buffer
;
; In: bx=offset to string, al=number of pairs
; Uses: ax,bx
;
; The string must fit all at once for this procedure to succeed.
; We test the keyboard buffer to see if there is room to do the copy.
; If not enough room, then the call fails!
;
StuffCodes2keybuffer proc
push cx
cmp flag_arrowkeys,0 ; Arrow and Xterm stuffing disabled?
je short @@exit ; Yes, then quit fast.
; Test for room to do the copy
call Check4Room ; Does the keyboard buffer have room
jnz short @@exit ; for AL pairs? NZ flag == NO ROOM, Exit!
@@loop:
cmp al,0
je @@exit
dec al
mov cl,byte ptr [cs:bx] ; ASCII value
inc bx
mov ch,byte ptr [cs:bx] ; Scan code
inc bx
push ax
call stuffkeyCX ; uses ax,cx
pop ax
jmp @@loop
@@exit:
pop cx
ret
StuffCodes2keybuffer endp
; Stuff cursor location into data area using Xterm codes
; In: al=Y=row, ah=Y=col, the cursor location in PC terms.
; bx=offset to data area
; Uses: ax,bx
; Xterm codes are ROW=X+' '+1, COL=Y+' '+1.
; Xterm_PAD==' '+1. Assume fake scan codes.
;
StuffLoc2buffer proc
add ah,Xterm_PAD ; coded col for Xterm
mov byte ptr [cs:bx],ah
inc bx
inc bx
add al,Xterm_PAD ; coded row for Xterm
mov byte ptr [cs:bx],al
ret
StuffLoc2buffer endp
; Stuff left button info into keyboard buffer
; In: al=row, ah=column
; Uses: ax
;
StuffLeftButton proc
push bx
mov bx,offset Button1_COL ; Offset to data area
call StuffLoc2buffer ; Stuff cursor location into buffer
mov bx,offset Button1_ESC ; Escape sequence for button 1
mov al,Button1_LEN ; Number of pairs in button 1 escape.
call StuffCodes2keybuffer ; Stuff escape seq into key buffer
pop bx
ret
StuffLeftButton endp
; Simulate press of button 3 on any mouse. Left release is mapped to
; the press of button three which normally follows button one. This button
; ends the marking of a region and maybe it copies it too, depending on the
; client program at the remote host end.
;
StuffRightButton proc
; In: al=row, ah=column
; Uses: ax
; We assume the keyboard buffer empty!
; Simplifies logic, but may fail.
push bx
mov bx,offset Button3_COL ; Data area pointer
call StuffLoc2buffer ; Stuff cursor location into buffer
mov bx,offset Button3_ESC ; Escape sequence for button 3
mov al,Button3_LEN ; Number of pairs in button 3 escape.
call StuffCodes2keybuffer ; Stuff escape seq into key buffer
pop bx
ret
StuffRightButton endp
;
; Simulate button2 press on any mouse.
;
StuffMiddleButton proc
; In: al=row, ah=column
; Uses: ax
; We assume the keyboard buffer empty!
; Simplifies logic, but may fail.
push bx
mov bx,offset Button2_COL ; Data area pointer
call StuffLoc2buffer ; Stuff cursor location into buffer
mov bx,offset Button2_ESC ; Escape sequence for button 2
mov al,Button2_LEN ; Number of pairs in button 1 escape.
call StuffCodes2keybuffer ; Stuff escape seq into key buffer
pop bx
ret
StuffMiddleButton endp
;
; Do Xterm selection by stuffing escapes into the keyboard buffer
; Our selection here maps a button1 drag into "press left", "move"
; and "press right", which is the 3-button Xterm standard for marking
; a region.
;
DoXtermButton1Button3 proc
cmp flag_editor,3 ; Is it Xterm mode?
jne short @@exit
push cx
mov ax,PositionLeft
mov cx,NextPositionLeft
cmp ax,cx
jc short @@no_swap ; not marked from right to left
xchg ax,cx ; now from left to right
@@no_swap:
; Send left button info
push cx
call offs2xy ; AX/lineSize --> al=quotient, ah=remainder
call StuffLeftButton ; stuff Xterm escape for button 1
; Send right button info, to simulate button3 on a 2-button mouse.
pop ax ; prep for integer division, AX=top
call offs2xy ; AX/lineSize --> al=quotient, ah=remainder
call StuffRightButton ; stuff Xterm escape for button 3
pop cx
@@exit:
ret
DoXtermButton1Button3 endp
;
; Stuff middle button (button 2) info into the keyboard buffer
; This button normally causes the remote client to insert the
; local pastebuffer (Xterm standard).
;
DoXtermButton2 proc
cmp flag_editor,3 ; Is it Xterm mode?
jne short @@exit
call GetMousePosition ;al=row, ah=col
call StuffMiddleButton
@@exit:
ret
DoXtermButton2 endp
;
; Stuff right button (button 3) info into the keyboard buffer
; This button normally causes the remote client to define the
; region after a left button was received (Xterm standard).
; This is the extra button on a PC 3-button mouse.
;
DoXtermButton3 proc
cmp flag_editor,3 ; Is it Xterm mode?
jne short @@exit
call GetMousePosition ;al=row, ah=col
call StuffRightButton
@@exit:
ret
DoXtermButton3 endp
;
; stuff2keybuffer --- Write characters into keyboard buffer
;
stuff2keybuffer proc ; stuff to keyboard buffer
mov flag_busy_stuffing,1 ; Don't let the timer interrupt
; re-enter this routine!
XPUSHA
xor cx,cx
xchg cl,lastChar ; character left from last attempt
or cl,cl ; 0 == nothing left
jnz short @@after_rd ; save character from last trial
@@loop:
call GetPastebuffer2AL ; Nothing returned if flag_pastebuffer == 0
mov cl,al ; else AL == char found in pastebuffer
jc short @@@exit ; nothing to stuff into keybuffer
@@after_rd:
push cx
cmp cl,0
mov ch,0 ; scancode, only relevant for ENTER
jz @@scan_code ; Potential trouble: wrong scan codes!
mov ch,1ch ; scancode for ENTER
@@scan_code:
call stuffkeyCX ; stuff CX to keyboard buffer, uses ax,cx
pop cx
jz short @@loop ; 0 == save was successful
mov lastChar,cl ; save for next time
jmp @@exit
@@@exit: ; Get here because pasting is finished.
mov lastChar,0
call StuffArrows ; Stuff arrow keys and Xterm sequences
@@exit:
XPOPA
mov flag_busy_stuffing,0 ; Let the timer interrupt
; re-enter this routine!
ret
stuff2keybuffer endp
;
; Move cursor by stuffing keyboard buffer with escapes or arrow keys.
;
StuffArrows proc
;
@@arrows:
;
; emacs/vi: If the target row is not equal to the present row, then move
; the cursor to column one of the same line before doing any
; further cursor motion. Logic from emacs/vi/jed/jove.
; matrix: Move to row first, then to column, no tricky cursor moves.
; xterm: Use the escape sequence \033 [ M cb cx cy
; for left button press.
;
cmp flag_arrowkeys,1 ; Arrow keys on?
je short @@test_emacs_vi
jmp @@exit ; No, then get out of here fast.
@@test_emacs_vi:
cmp flag_editor,1 ; Using a method suitable for emacs/vi?
jne short @@test_matrix
jmp @@do_emacs_vi
@@test_matrix:
cmp flag_editor,2 ; Using a method suitable for matrix editor?
jne short @@test_xterm ; Test Xterm escapes
jmp @@do_matrix ; Do matrix method
@@test_xterm:
cmp flag_editor,3
je short @@do_xterm
jmp @@exit
;
@@do_xterm:
cmp flag_doButton13,TRUE
jne short @@do_xterm1
call DoXtermButton1Button3 ; Send button 1 + button 3.
mov flag_doButton13,FALSE
jmp short @@do_xterm_exit
@@do_xterm1:
cmp flag_doButton2,TRUE
jne short @@do_xterm2
call DoXtermButton2 ; Send button2 info
mov flag_doButton2,FALSE
jmp short @@do_xterm_exit
@@do_xterm2:
cmp flag_doButton3,TRUE
jne short @@do_xterm3
call DoXtermButton3 ; Send button3 info
mov flag_doButton3,FALSE
jmp short @@do_xterm_exit
@@do_xterm3:
mov al,col_target
cmp al,col_present
jne short @@do_xterma
mov al,row_present
cmp al,row_target
jne short @@do_xterma
jmp short @@do_xterm_exit
@@do_xterma: ; We assume the keyboard buffer empty!
; Simplifies logic, but may fail.
mov ah,col_target ; AX=Where to report cursor
mov al,row_target
push ax
call StuffLeftButton ; Stuff Xterm escape into keybuffer
pop ax
mov col_present,ah
mov row_present,al
@@do_xterm_exit:
jmp @@exit
;
@@do_emacs_vi:
mov al,row_present
cmp row_target,al
je short @@downarrow ; row_target == row_present
@@arrow_loop:
cmp col_present,0
je short @@downarrow ; col_present == 0
call LeftArrow
jz short @@arrow_loop_continue ; it worked
jmp @@exit ; it failed, keybuffer full
@@arrow_loop_continue:
dec col_present ; move one left
jmp @@arrow_loop
;
@@do_matrix:
@@downarrow:
mov al,row_present
cmp row_target,al
je short @@rightarrow ;row_target == row_present
jl short @@uparrow ;row_target < row_present
;
; row_target > row_present
;
call DownArrow
jz short @@down_continue ; worked
jmp @@exit ; failed, keybuffer full
@@down_continue:
inc row_present ; move one row down
jmp @@downarrow
;
; row_target < row_present
;
@@uparrow: ;row_target < row_present
call UpArrow
jz short @@up_continue ; worked
jmp @@exit ; failed, keybuffer full
@@up_continue:
dec row_present ; move one up
jmp @@downarrow
@@rightarrow:
mov al,col_present
cmp col_target,al
je short @@exit ; col_target == col_present
jl short @@leftarrow ; col_target < col_present
;
; col_target > col_present
;
call RightArrow
jz short @@right_continue ; worked
jmp @@exit ; failed, keybuffer full
@@right_continue:
inc col_present ; move one right
jmp @@rightarrow
;
; col_target < col_present
;
@@leftarrow:
call LeftArrow
jz short @@left_continue ; worked
jmp @@exit ; failed, keybuffer full
@@left_continue:
dec col_present ; move one left
jmp @@rightarrow
@@exit:
ret
StuffArrows endp
;
; Get mouse position from handler's last call
; OUT: al=row, ah=col
; USES: AX
GetMousePosition proc
PUSHR <dx,cx>
mov cx,current_X
shr cx,1 ; Get target column position in cl
shr cx,1
shr cx,1
mov dx,current_Y
shr dx,1 ; Get target row position in dl
shr dx,1
shr dx,1
mov al,dl
mov ah,cl
POPR <cx,dx>
ret
GetMousePosition endp
;
; Set cursor position. Later, the keyboard buffer is stuffed by "stuff2keybuffer".
; Uses: AX
set_cursor proc
PUSHR <bx,ds>
call GetMousePosition ;al=row, ah=col
mov col_target,ah
mov row_target,al
; Get current text cursor position from BIOS variable
mov ax,40h ; Segment of DOS bios
mov ds,ax
mov ah,0
mov al,byte ptr [ds:62h] ;Get current video page number
add al,al ; AL=2*AL
add al,50h ; 50h=cursor position bios data (8 16-bit words)
mov bx,ax ; BX=offset in segment 40h
mov ax,[ds:bx] ;Get cursor position for current page
mov row_present,ah
mov col_present,al
mov lasttime,0
mov lasttime+2,0 ; shut off click timing
@@exit:
POPR <ds,bx> ; PUSHR <bx,ds>
ret
set_cursor endp
; NB: The next two variables should be in this order before pastebuf
; so that /U can de-install the TSR.
XPC_pspadr dw 0 ; psp address of installed XPC-mouse
ENDPAIR dw offset lastpair ; Pointer to actual end
BUFLEN dw BUFFERLEN ; Buffer size in bytes
; buffer for read characters,
; can overwrite initialisation code
pastebuf equ $
DE_INSTALL equ 2 ; See option /U, procedure "get_opt" below.
REACTIVATE equ 3 ; See option /R
NOT_INSTALLED equ 40h ; FLAG for driver not installed.
ALL_OK equ 41h ; FLAG for all go.
WRO_VEC equ 42h ; FLAG for wrong vector detected.
MOUSE_FN equ 80h ; new function of int 16h that detects
; previous installation of the program
INST_HND equ 67h ; tell int 16 to reinstall mouse handler
IDENTCODE equ 16879 ; A 16-bit number used to test validity of /U
; and /R options.
TESTCPU macro
; Test for 80188 cpu or later. See startup code. Not used for XT.
if not XT
mov cl,33 ; Test for 80188 or successor
shl ax,cl
or cl,cl ; 188+ maximally shift 32 positions
mov dx,offset wro_cpu_str
jz @@errexit
endif ; not XT
endm
TESTBIOS macro
if not XT
; Test for modern Bios with int 16,5. See startup code. Not used for XT.
; Equipment check for enhanced keyboard.
mov ax,40h
mov es,ax
test byte ptr [es:96h],10000b ; enhanced keyboard installed ?
jz @@errexit
endif ; not XT
endm
; Local variables used to parse command line. These get wiped out by
; the paste buffer, which writes over this area.
;
quiet_flag db FALSE ; TRUE to display everything, FALSE defeats
copying_flag db FALSE ; TRUE to display copying info
counter_Xoption db 0 ; Counter for number of /M and /X options.
how_to_flag db FALSE ; TRUE if to display only How-To string
; change interrupts and install mouse handler
;
; GET OPTIONS. Returns special options in ah.
;
get_opt proc
mov si,80h ; si => command line parameters
seges
lodsb ; count
mov bh,0
mov bl,al
mov es:[si+bx],bh ; 0
or al,al
jnz @@findslash
jmp @@parm_done
@@findslash:
seges
lodsb
or al,al
jz @@parm_done
cmp al," "
jz short @@findslash ; +DEC CX
cmp al,"/"
jz short @@good_sep
cmp al,"-"
jnz @@parm_err
@@good_sep:
; Valid options to return in register ah:
; DE_INSTALL, REACTIVATE
;
@@loop: ; Added some documentation of steps
seges ; on 1-Nov-1994
lodsb
@@HELP_setup:
cmp al,'?' ; Got ? on command line
jz short @@parm_err
and al,not ('a'-'A') ; toupper
cmp al,'H' ; Got /H on command line
jnz @@HELP_setup_exit
mov how_to_flag,TRUE
jz short @@parm_err
@@HELP_setup_exit:
@@U_setup:
cmp al,'U' ; Got /U for uninstall
mov ah,DE_INSTALL
jnz short @@U_setup_exit
jmp @@exit
@@U_setup_exit:
@@R_setup:
cmp al,'R' ; Got /R for reactivate driver
mov ah,REACTIVATE
jnz short @@R_setup_exit
jmp @@exit
@@R_setup_exit:
;
; Loop on the other command line options
;
@@C_setup:
cmp al,'C' ; Got /C, display copying info
jne short @@C_setup_exit
mov copying_flag,1
jmp @@findslash
@@C_setup_exit:
@@P_setup:
cmp al,'P' ; Got /P, defeat pastebuffer
jne short @@P_setup_exit
mov flag_pastebuffer,0
jmp @@findslash
@@P_setup_exit:
@@K_setup:
cmp al,'K' ; Got /K, defeat arrow keys
jne short @@K_setup_exit
mov flag_arrowkeys,0
jmp @@findslash
@@K_setup_exit:
@@A_setup:
cmp al,'A' ; Got /A, set emacs, matrix, xterm modes
jnz short @@A_setup_exit
call parse_num ; Get number nnn after '/A'
cmp ax,MAX_of_A ; Valid options are 1,2,...,(MAX_of_A)-1
jae short @@A_setup1
cmp ax,1
jb short @@A_setup1
mov flag_editor,al
@@A_setup1:
jmp @@findslash
@@A_setup_exit:
@@N_setup:
cmp al,'N' ; Got /N for no mouse handler saving
jnz short @@N_setup_exit
mov cs:flag_int21,TRUE
jmp @@findslash
@@parm_err:
mov ah,FALSE
jmp @@exit
@@parm_done:
mov ah,TRUE
jmp @@exit
@@N_setup_exit:
@@Q_setup:
cmp al,'Q' ; Got /Q for quiet startup mode
jnz short @@Q_setup_exit
mov cs:quiet_flag,TRUE
jmp @@findslash
@@Q_setup_exit:
@@M_setup:
cmp al,'M' ; Got /M for monochrome video mode
jnz short @@M_setup_exit
mov al,119 ; XOR byte mask for monochrome == /X119
jmp short @@X_setup1
@@M_setup_exit:
@@X_setup:
cmp al,'X' ; Got /X for XOR mask ddd
jnz short @@X_setup_exit
call parse_num ; Get number nnn after '/X'
cmp ax,255 ; Value ddd==119 for monochrome
ja @@parm_err
cmp ax,0
jb short @@parm_err
@@X_setup1:
mov xor_mask,al
inc counter_Xoption
jmp @@findslash
@@X_setup_exit:
@@B_setup:
cmp al,'B' ; Got /B for new buffer size in paragraphs
jnz short @@B_setup1_exit
call parse_num ; Get number nnn after '/B'
cmp ax,BUFFERLEN/16 ; Don't let it get bigger than BUFFERLEN
ja @@parm_err ; But ZERO is OK!
shl ax,1 ; Times 2
shl ax,1 ; Times 4
shl ax,1 ; Times 8
shl ax,1 ; Times 16
mov cs:BUFLEN,ax
jmp @@findslash
@@B_setup1_exit:
@@T_setup:
cmp al,'T' ; Got /T for for Timer interrupt option
jne @@T_setup_exit
mov cs:flag_int1c,TRUE ;Enable timer click code int 1ch
jmp @@findslash
@@T_setup_exit:
jmp @@findslash
@@exit:
ret
get_opt endp
parse_num proc
mov bx,10
mov ax,0
mov dh,0
@@addloop:
seges
mov dl,[si]
or dl,dl
jz short @@done
inc si
sub dl,'0'
jc short @@done
cmp dl,9
ja short @@done
push dx
mul bx
pop dx
add ax,dx
jmp short @@addloop
@@done:
ret
parse_num endp
inst_tst proc ; exit: Z = installed
PUSHR <ax,dx,cx>
mov ah,MOUSE_FN ; test for installed, call patched int16h
mov al,MOUSE_FN
push ax
int 16h ; es:bx points to pastebuf
pop dx
dec dh
cmp ah,dh
jnz short @@exit
cmp cx,IDENTCODE
@@exit:
POPR <cx,dx,ax>
ret
inst_tst endp
cmp_fptr proc ; cmp ax:bx and cx:dx
XPUSHA
mov si,0
mov di,0
; si:ax *= 16
rept 4
shl ax,1
rcl si,1
endm
add ax,bx
adc si,0
; di:cx *= 16
rept 4
shl cx,1
rcl di,1
endm
add cx,dx
adc di,0
cmp cx,ax
jnz short @@exit
cmp si,di
@@exit:
XPOPA
ret
cmp_fptr endp
ms_hnd_ptr dw 0,0
re_activate proc
LOCAL hndadr:DWORD = AUTO_SIZE
push bp
mov bp,sp
sub sp,AUTO_SIZE
PUSHR <ds,es>
call inst_tst
mov al,NOT_INSTALLED
jnz short @@exit
mov ah,MOUSE_FN ; far address of pastebuf is in registers es:bx
mov al,MOUSE_FN
int 16h
; Load bx with pointer to proc InstallMouseHandler
sub bx,pastebuf-InstallMouseHandler
mov word ptr hndadr,bx
mov bx,es
mov word ptr hndadr+2,bx
call dword ptr [hndadr]
@@exit:
POPR <es,ds>
add sp,AUTO_SIZE
pop bp
ret
re_activate endp
RSTVEC macro vec,old_vec_dist
mov bx,pcmoffs
sub bx,old_vec_dist
lds dx,[es:bx]
mov ax,(25h shl 8) + vec ; set vector
int 21h
endm
CMPVEC macro vec,new_vec_dist
mov ax,(35h shl 8) + vec ; get vector
int 21h ; to es:bx
mov ax,es
mov cx,pcmseg
mov dx,pcmoffs
sub dx,new_vec_dist
call cmp_fptr ; cmp ax:bx and cx:dx
jnz @@wrong_vec
endm
de_inst proc
LOCAL pcmoffs,pcmseg:WORD,safeflg:BYTE,tckflg:BYTE = AUTO_SIZE
push bp
mov bp,sp
sub sp,AUTO_SIZE
PUSHR <ds,es>
call inst_tst
mov al,NOT_INSTALLED
jz short @@cont_de_inst
jmp @@goexit
@@cont_de_inst:
; now test for all patched vectors, if they point to xpcmouse
mov ah,MOUSE_FN ; far address pastebuf returned
mov al,MOUSE_FN ; in registers es:bx
int 16h
mov pcmoffs,bx ; Offset to pastebuf
mov ax,es
mov pcmseg,ax ; Segment of installed xpc-mouse
push bx
sub bx,pastebuf-flag_int1c
mov al,es:[bx]
mov tckflg,al ; use flag_int1c of installed copy
pop bx
sub bx,pastebuf-flag_int21
mov al,es:[bx]
mov safeflg,al ; use flag_int21 of installed copy
cmp safeflg,TRUE
jz short @@no_21_test
CMPVEC 21h,pastebuf-new_21h
@@no_21_test:
CMPVEC 16h,pastebuf-new_16h
CMPVEC 10h,pastebuf-new_10h
cmp tckflg,TRUE
jnz short @@de_inst
CMPVEC 1ch,pastebuf-new_1ch
jmp short @@de_inst
@@wrong_vec:
mov al,WRO_VEC
@@goexit:
jmp short @@exit
@@de_inst:
cmp safeflg,TRUE
jz short @@no_21_deinst
RSTVEC 21h,pastebuf-old_21h
@@no_21_deinst:
RSTVEC 16h,pastebuf-old_16h
RSTVEC 10h,pastebuf-old_10h
cmp tckflg,TRUE
jnz short @@no_tick2
RSTVEC 1ch,pastebuf-old_1ch
@@no_tick2:
; reset driver is done at end of last exec, too
mov ax,0h
int 33h ; reset mouse driver & HW & interrupt handler
mov es,pcmseg ; segment of installed xpc-mouse
mov bx,pcmoffs ; offset into that segment
sub bx,pastebuf-killed_flg ; get offset to killed_flg in "new_21h"
mov byte ptr [es:bx],TRUE ; Prevent re-entry of "new_21h"
mov bx,pcmoffs ; offset to pastebuf
sub bx,pastebuf-XPC_pspadr ; offset to storage word
mov es,[es:bx] ; Get psp address word
mov ah,49h ; free memory
int 21h
mov al,ALL_OK
jmp @@exit
@@exit:
POPR <es,ds>
add sp,AUTO_SIZE
pop bp
ret
de_inst endp
init proc
mov ax,es
mov cs:XPC_pspadr,ax ; Save a copy in resident code
mov ax,cs
mov ds,ax
call get_opt
push ax
; Output copying message and quit?
cmp cs:copying_flag,FALSE
jz short @@no_copying
pop ax
mov dx,offset copying
jmp @@do_exit
@@no_copying:
cmp cs:quiet_flag,TRUE
jz short @@no_onsign
mov dx,offset onsign
mov ah,9
int 21h
@@no_onsign:
pop ax
cmp cs:how_to_flag,TRUE
jnz short @@no_onsign1
jz @@do_howto_exit
@@no_onsign1:
cmp ah,TRUE
jz short @@cont_inst
cmp ah,FALSE
mov dx,offset help_str
jz @@do_exit
cmp ah,REACTIVATE
jnz short @@tst_de_inst
call re_activate
cmp al,NOT_INSTALLED
jz short @@not_yet1
mov dx,offset re_inst_str
jmp @@do_exit
@@tst_de_inst:
cmp ah,DE_INSTALL
jnz short @@cont_inst
call de_inst
cmp al,NOT_INSTALLED
@@not_yet1:
mov dx,offset not_yet_str
jz @@do_exit
cmp al,ALL_OK
mov dx,offset ok_de_inst
jz @@do_exit
mov dx,offset wro_de_inst
jmp @@do_exit
@@cont_inst:
TESTCPU ; Test for 80188 cpu or later. See macro above.
TESTBIOS ; Test for modern bios. See macro above.
; use function 21h (instead of 0) to ensure that new
; mouse driver is installed
mov ax,21h ; Test, if mouse driver installed
int 33h
inc ax ; installed => 0
jz short @@mouse_there
mov dx,offset nomouse_str
@@errexit:
mov ah,9
int 21h
mov dx,offset noins_str
@@do_exit:
mov ah,9
int 21h
mov ax,4c01h ; errorlevel 1 == no mouse driver
int 21h
@@mouse_there:
call inst_tst
jnz short @@install
@@do_howto_exit:
mov dx,offset help_switches
mov ah,9
int 21h
mov dx,offset how_to
mov ah,9
int 21h
cmp cs:how_to_flag,FALSE
je @@exit02
mov ax,4c03h ; errorlevel 3 == message exit
int 21h
@@exit02:
mov dx,offset msgstr
mov ah,9
int 21h
mov ax,4c02h ; errorlevel 2 == re-installed
int 21h
@@install:
; Set buffer length variable
mov ax,cs:BUFLEN ; Get ending address of the
add ax,offset pastebuf-1 ; Paste Buffer
mov cs:EndOfBuffer,ax ; and save it
; See if the video mode is appropriate for the /Xddd mask
cmp cs:counter_Xoption,0 ; Over-ride on command line?
jnz short @@video_OK
; Option /M for monochrome Video mode (/M==/X119).
push ds
mov ax,40h ; Segment of bios
mov ds,ax
cmp byte ptr [ds:49h],7 ; BIOS current video mode mono?
pop ds
jnz short @@video_OK
mov xor_mask,119 ; Use /X119 for mono
@@video_OK:
; free environment
; Space managed by DOS can be re-used.
;
mov es,cs:XPC_pspadr
mov es,[es:2ch] ; segment address of environment
mov ah,49h ; free memory
int 21h
mov ax,3516h
int 21h ; get vector
mov word ptr old_16h,bx
mov word ptr cs:[old_16h+2],es
mov ax,351ch
int 21h ; get vector
mov word ptr old_1ch,bx
mov word ptr cs:[old_1ch+2],es
mov ax,3510h
int 21h
mov word ptr cs:[old_10h],bx
mov word ptr cs:[old_10h+2],es
; with option /N don't install int 21h patch
cmp cs:flag_int21,TRUE
jz short @@no_21_inst
mov ax,3521h
int 21h
mov word ptr cs:[old_21h],bx
mov word ptr cs:[old_21h+2],es
mov dx,offset new_21h
mov ax,2521h ; set vect
int 21h
@@no_21_inst:
mov dx,offset new_10h
mov ax,2510h ; set vect
int 21h
mov dx,offset new_16h
mov ax,2516h ; set vect
int 21h
cmp cs:flag_int1c,FALSE
jz short @@no_tick_set
mov dx,offset new_1ch
mov ax,251ch ; set vect
int 21h
@@no_tick_set:
call InstallMouseHandler
cmp cs:quiet_flag,TRUE
jz short @@terminate
mov dx,offset how_to
mov ah,9
int 21h
mov dx,offset worked
mov ah,9
int 21h
@@terminate:
; Compute how many paragraphs are to be resident.
; This count adds is code length plus paste buffer length. The
; paste buffer has by design a maximum length of BUFFERLEN bytes.
;
mov dx,cs:BUFLEN ; Desired buffer length
add dx,offset pastebuf ; resident code len + BUFLEN
add dx,15+256 ; Roundup + EXE header size
shr dx,1 ; dx --> (end_mouse - begin_resident+15+256)/2
shr dx,1 ; dx --> (end_mouse - begin_resident+15+256)/4
shr dx,1 ; dx --> (end_mouse - begin_resident+15+256)/8
shr dx,1 ; dx --> (end_mouse - begin_resident+15+256)/16
mov ax,3100h
int 21h ; terminate stay resident
init endp
copying:
db 'Copyright (c) 1994 Jürgen G. Weber and G.B. Gustafson',13,10
db 'xPC-Mouse is free software, distributed under the terms of the',13,10
db 'GNU General Public License. For details, see the file COPYING.',13,10
db 10
db 'Jürgen G. Weber',13,10
db 'Wiesentalstraße 1',13,10
db 'D-74523 Schwäbisch Hall',13,10
db 'Germany',13,10
db 'email: weberj@dia.informatik.uni-stuttgart.de',13,10
db 10
db 'Grant B. Gustafson',13,10
db '113 JWB Math Dept Univ Utah',13,10
db 'Salt Lake City, UT 84112 USA',13,10
db 'email: gustafson@math.utah.edu',13,10
db '$'
onsign db 13,10,'xPC-Mouse, version ',PVERSION,13,10
db 'Copyright (c) 1994 Jürgen G. Weber and G.B. Gustafson',13,10
db 'Free for personal use under the Gnu license agreement.',13,10
db 10,'$'
how_to:
db 'MOUSE BUTTON FUNCTION',13,10
db 'Mouse 1 (1/6 second) ... Position cursor',13,10
db 'Mouse 2 ................ Paste text',13,10
db 'Drag Mouse 1 ........... Copy text',13,10
db 'Double-click Mouse 1 ... Copy word',13,10
db 'CTRL-Mouse 2 ........... Paste text + ENTER',13,10
db 'ALT-Mouse 2 ............ Mouse 3 duplicate',13,10
db 'SHIFT-Mouse 1 .......... Cursor feature on/off ',13,10
db 'SHIFT-ALT-Mouse 1 ...... Toggle methods /A1-/A3',13,10
db 'SHIFT-Mouse 2 .......... Paste feature on/off',13,10
db '$'
worked db 13,10
db 'xPC-Mouse is installed. Use "xPCmouse /U" to un-install.',13,10,'$'
msgstr db 13,10
db 'xPC-Mouse was already installed.',13,10,'$'
not_yet_str db 13,10, 'xPC-Mouse was not installed yet.',13,10,'$'
ok_de_inst db 13,10, 'xPC-Mouse is un-installed.',13,10,'$'
re_inst_str db 13,10, 'xPC-Mouse is re-activated.',13,10,'$'
wro_de_inst db 13,10, 'Could not un-install xPC-Mouse.',13,10,'$'
nomouse_str db 13,10,7,'No mouse driver found or driver too old.',13,10,'$'
noins_str db 'xPC-Mouse not installed.',13,10,'$'
wro_cpu_str db 'xPC-Mouse needs at least an 80286 with',13,10
db 'extended keyboard support.',13,10,'$'
help_str db 13,10,'Options: /U : Un-install xPC-Mouse',13,10
db ' /Q : Quiet, no messages',13,10
db ' /R : Re-activate xPC-Mouse',13,10
db ' /M : Monochrome video mode (equals /X119)',13,10
db ' /Xddd : Highlight XOR mask ddd (default /X80)',13,10
db ' /Bddd : Buffer size ddd paragraphs (16*ddd bytes)',13,10
db ' /T : Enable timer int 1Ch patch',13,10
db ' /N : Defeat int 21h patch',13,10
db ' /P : Defeat pastebuffer use',13,10
db ' /K : Defeat arrow key emulation',13,10
db ' /A1 : Emacs/vi arrow key method (default)',13,10
db ' /A2 : Matrix arrow key method',13,10
db ' /A3 : Xterm escape sequence method',13,10
help_switches:
db 'Info: /C : Display copying information',13,10
db ' /? : Display help text',13,10
db ' /H : Display mouse button assigments',13,10
db 13,10,'$'
; Insure source file is long enough when loaded into memory
; so that the pastebuffer is the proper size.
;
if ($-pastebuf) lt BUFFERLEN
db BUFFERLEN-($-pastebuf) dup (?)
endif
end_mouse equ pastebuf+BUFFERLEN
code ends
; Stack segment is only used during initialization
stck segment para stack 'stack'
db 256 dup (?)
stck ends
end init
comment *
GNU PUBLIC LICENSE.
This software is released as copyrighted material under the GNU PUBLIC
LICENSE:
NO WARRANTY
Because xPC-Mouse is licensed free of charge, absolutely no warranty
is provided, to the extent permitted by applicable state law. Except
when otherwise stated in writing, Jürgen G. Weber and Grant B.
Gustafson provides xPC-Mouse "as is" without warranty of any kind,
either expressed or implied, including, but not limited to, the
implied warranties of merchantability and fitness for a particular
purpose. The entire risk as to the quality and performance of the
program is with you. Should the xPC-Mouse program prove defective,
you assume the cost of all necessary servicing, repair or correction.
In no event unless required by applicable law will Grant B. Gustafson
and Jürgen G. Weber and/or any other party who may modify and
redistribute xPC-Mouse be liable to you for damages, including any
lost profits, lost monies, or other special, incidental or
consequential damages arising out of the use or inability to use
(including but not limited to loss of data or data being rendered
inaccurate or losses sustained by third parties or a failure of the
program to operate with programs not distributed by Grant B.
Gustafson and Jürgen G. Weber) the program, even if you have been
advised of the possibility of such damages, or for any claim by any
other party.
NO COST?
This software is provided free of charge to individuals and educational
institutions. Money is not requested.
POSTCARDS?
Postcards and comments are welcome!
Jürgen G. Weber GB Gustafson
Wiesentalstraße 1 113 JWB Math Dept Univ Utah
D-74523 Schwäbisch Hall Salt Lake City, UT 84112
Germany - European Union USA
* ; End comment